/**
 * @author Ahammer
 * @date   2009 05
 * @update added 16 bit support
 */

/*
 * This file is part of Iqm.
 * Copyright (c) 2010-2011 Helmut Ahammer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package op;

import java.awt.RenderingHints;
import java.awt.image.DataBuffer;
import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.JAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;

import main.IqmTools;

/**
 * This is the main image processing class
 * There exist two approaches:
 * A user defined JAI operator is just called 
 * or:
 * The actual processing is implemented in this class 
 */
public class IqmCalcValueOperator{ 


  public IqmCalcValueOperator() {
	  //WARNING: Don't declare fields here
	  //Fields declared here aren't thread safe!   
  }
  /**
   * 
   * @param ParametrBlockJAI pb
   */
  public Object run(ParameterBlockJAI pbJAI){
	  Object ob = null;
	  //ob = JAI.create("IqmCalcValue".toLowerCase(), pb, null);  
	  
	  PlanarImage pi1 = (PlanarImage) pbJAI.getSource(0);	
	  int    calc 	 	   = pbJAI.getIntParameter(0);
	  double v 			   = pbJAI.getDoubleParameter(1);
	  double value[] 	   = {v, v, v};
	  int    resultOptions = pbJAI.getIntParameter(2);
	  
	  String type        = IqmTools.getImgTyp(pi1);
	  double typeGreyMax = IqmTools.getImgTypeGreyMax(pi1);
	  
	  //RenderingHints rh = new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));	
	  RenderingHints rh = null;	
	  ParameterBlock pb = new ParameterBlock();
	  if ((calc == 0)||(calc == 1)||(calc == 2)||(calc == 3)||(calc == 4)||(calc == 5)){
		  pb.addSource(pi1);
		  pb.add(DataBuffer.TYPE_DOUBLE);
		  pi1 = JAI.create("format", pb);  
	  }
	  if ((calc == 6)||(calc == 7)||(calc == 8)){
//		  pb.addSource(pi1);
//		  pb.add(DataBuffer.TYPE_BYTE);
//		  pi1 = JAI.create("format", pb);  
	  }
		  
	  pb.removeSources();
	  pb.removeParameters();
		  
	  if (calc == 0){ //Add
		  pb.addSource(pi1);	
		  pb.add(value);	
		  ob= JAI.create("AddConst", pb, rh);
	  }
	  if (calc == 1){ //Subtract Const from Image
		  pb.addSource(pi1);	
		  pb.add(value);	
		  ob= JAI.create("SubtractConst", pb, rh);
	  }
	  if (calc == 2){ //Multiply
		  pb.addSource(pi1);	
		  pb.add(value);	
		  ob= JAI.create("MultiplyConst", pb, rh);
	  }
	  if (calc == 3){ //Divide
		  pb.addSource(pi1);	
		  pb.add(value);	
		  ob= JAI.create("DivideByConst", pb, rh);
	  }
	  if (calc == 4){ //Subtract Image From Const
		  pb.addSource(pi1);	
		  pb.add(value);	
		  ob= JAI.create("SubtractFromConst", pb, rh);
	  }
	  if (calc == 5){ //Divide Into Constant
		  pb.addSource(pi1);	
		  pb.add(value);	
		  ob= JAI.create("DivideIntoConst", pb, rh);
	  }
	  if (calc == 6){ //AND
		  pb.addSource(pi1);
//		  Integer[] intValue = new Integer[3];
//		  intValue[0] = (int) Math.round(value[0]);
//		  intValue[1] = (int) Math.round(value[1]);
//		  intValue[2] = (int) Math.round(value[2]);
		  
		  int[] intValue = {(int) Math.round(value[0])};
		  pb.add(intValue);	
		  ob= JAI.create("AndConst", pb, rh);
	  }
	  if (calc == 7){ //OR
		  pb.addSource(pi1);	
//		  Integer[] intValue = new Integer[3];
//		  intValue[0] = (int) Math.round(value[0]);
//		  intValue[1] = (int) Math.round(value[1]);
//		  intValue[2] = (int) Math.round(value[2]);
		  
		  int[] intValue = {(int) Math.round(value[0])};
		  pb.add(intValue);	
		  ob= JAI.create("OrConst", pb, rh);
	  }
	  if (calc == 8){ //XOR
		  pb.addSource(pi1);	
//		  Integer[] intValue = new Integer[3];
//		  intValue[0] = (int) Math.round(value[0]);
//		  intValue[1] = (int) Math.round(value[1]);
//		  intValue[2] = (int) Math.round(value[2]);

		  int[] intValue = {(int) Math.round(value[0])};
		  pb.add(intValue);	
		  ob= JAI.create("XorConst", pb, rh);
	  }
	  
	  //--------------------------------------------------------------------
	  if (resultOptions == 0){ //clamp to byte
	      pb.removeSources();
	      pb.removeParameters();
		  pb.addSource(ob);
		  if (type == "RGB")    pb.add(DataBuffer.TYPE_BYTE);
		  if (type == "8 bit")  pb.add(DataBuffer.TYPE_BYTE);
		  if (type == "16 bit") pb.add(DataBuffer.TYPE_USHORT);
		  ob = JAI.create("format", pb);  	  
	  }
	  if (resultOptions == 1){ //normalize to byte
			pb.removeSources();
			pb.removeParameters();
			pb.addSource(ob);
			RenderedOp extrema = JAI.create("extrema", pb);
		    double[] minVec = (double[])extrema.getProperty("minimum");
		    double[] maxVec = (double[])extrema.getProperty("maximum");
		    double min = minVec[0];
		    double max = maxVec[0];
		
		    pb.removeSources();
			pb.removeParameters();
			pb.addSource(ob);
		    pb.add(new double[] {(typeGreyMax/(max-min))}); //Rescale 
		    pb.add(new double[] {((typeGreyMax*min)/(min-max))}); //offset
			ob = JAI.create("rescale", pb); 
		 
			pb.removeSources();
		    pb.removeParameters();
			pb.addSource(ob);
			if (type == "RGB")    pb.add(DataBuffer.TYPE_BYTE);
			if (type == "8 bit")  pb.add(DataBuffer.TYPE_BYTE);
			if (type == "16 bit") pb.add(DataBuffer.TYPE_USHORT);
			ob = JAI.create("format", pb);  	 
	  }

	  if (resultOptions == 2){ //Actual
		  //does nothing
	  }
	  return ob;
  }
}
